using System;
using System.Collections.Generic;
using System.Globalization;
using Felbot.Interface.Conversations;
using Felbot.Interface.Users;
using Felbot.Profiles;
using Felbot.Scripting;
using Felbot.IO;

namespace Felbot.Interaction {
    /// <summary>
    /// This class is the command processor.
    /// </summary>
    public static class CommandProcessor {
        /// <summary>Called to check for commands in messages.</summary>
        /// <param name="a_csSource">The command's source object.</param>
        /// <param name="a_sText">The text.</param>
        /// <returns>
        /// A boolean determining whether the text shall be sent to Battle.net
        /// after processing (whether no command was found or the command
        /// specifically says to not block it). False to send to Battle.net.
        /// </returns>
        public static bool ProcessCommand(CommandSource source, string text) {
            if (!ProfileControl.Global.GetSetting("Interaction", "CommandsEnabled").ToBoolean(true))
                return false;

            #region Declare and Define Local Variables Used in Commands
            string[] commands;
            string commandText = "";
            string[] commandParameters;
            string botUsername = frmProfile.GetForm(source.Profile.ProfileName).PacketThread.UniqueUsername;
            string trigger = source.Profile.GetSetting("Commands", "Trigger").ToString("!");
            string globalTrigger = ProfileControl.Global.GetSetting("Interaction", "Trigger").ToString("!!");
            #endregion

            #region Trigger Command
            if (text == "?trigger" && trigger != "?") {
                return ProcessCommand(source, trigger + "trigger");
            }
            #endregion

            #region Parse for Trigger
            if (source.Place == CommandSourcePlace.InBot || source.Place == CommandSourcePlace.InBotExternal) {
                if (text.StartsWith("//") && text.Length > 2 && text.Substring(2, 1) != "/") {
                    return ProcessCommand(new CommandSource(CommandSourcePlace.InBotExternal, source.User, source.Profile), text.Substring(1));
                } else if (text.StartsWith("/") && text.Length > 1 && text.Substring(1, 1) != "/") {
                    commandText = text.Substring(1);
                } else {
                    return false;
                }
            } else {
                if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerProfile").ToBoolean(true) &&
                           text.StartsWith(trigger, StringComparison.CurrentCultureIgnoreCase)) {
                    commandText = text.Substring(trigger.Length);
                } else if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerGlobal").ToBoolean(true) &&
                           text.StartsWith(globalTrigger)) {
                    commandText = text.Substring(globalTrigger.Length);
                } else if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerUsername").ToBoolean(true) &&
                           text.StartsWith(botUsername + ": ", StringComparison.CurrentCultureIgnoreCase) ||
                           text.StartsWith(botUsername + ", ", StringComparison.CurrentCultureIgnoreCase)) {
                    commandText = text.Substring(botUsername.Length + 2);
                } else if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerUsername").ToBoolean(true) &&
                           text.StartsWith(source.Profile.ProfileName + ": ", StringComparison.CurrentCultureIgnoreCase) ||
                           text.StartsWith(source.Profile.ProfileName + ", ", StringComparison.CurrentCultureIgnoreCase)) {
                    commandText = text.Substring(source.Profile.ProfileName.Length + 2);
                } else if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerOps").ToBoolean(true) &&
                           text.StartsWith("ops, ", StringComparison.CurrentCultureIgnoreCase) ||
                           text.StartsWith("ops: ", StringComparison.CurrentCultureIgnoreCase)) {
                    if (frmProfile.GetForm(source.Profile.ProfileName).Channel.You.HasOps)
                        commandText = text.Substring(5);
                } else if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerBots").ToBoolean(true) &&
                           text.StartsWith("bots, ", StringComparison.CurrentCultureIgnoreCase) ||
                           text.StartsWith("bots: ", StringComparison.CurrentCultureIgnoreCase)) {
                    commandText = text.Substring(6);
                } else if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerBots").ToBoolean(true) &&
                           text.StartsWith("felbots, ", StringComparison.CurrentCultureIgnoreCase) ||
                           text.StartsWith("felbots: ", StringComparison.CurrentCultureIgnoreCase)) {
                    commandText = text.Substring(9);
                } else if (ProfileControl.Global.GetSetting("Interaction", "CommandsTriggerlessWhisper").ToBoolean(false) && source.Place == CommandSourcePlace.Whisper) {
                    commandText = text;
                } else {
                    return false;
                }
            }
            #endregion

            #region Final Command Parsing and Xml Command to Script Control Routing
            commandText = " " + commandText;
            commands = commandText.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < commands.Length; i++) {
                commandText = commands[i];
                if (commandText.Length < 2)
                    continue;
                if (!commandText.StartsWith(" "))
                    continue;
                commandText = commandText.Substring(1);
                commandParameters = commandText.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

                if (ProfileControl.Global.GetSetting("Interaction", "CommandsCrossProfile").ToBoolean(false)) {
                    foreach (Profile profile in ProfileControl.GetOpenProfiles) {
                        if (commandText.Equals(profile.ProfileName, StringComparison.CurrentCultureIgnoreCase)) {
                            return ProcessCommand(new CommandSource(CommandSourcePlace.InBot, source.User, profile), "/" + commandText);
                        }
                    }
                }

                foreach (XmlCommand command in CommandControl.CommandList) {
                    if (command.Aliases.Contains(commandParameters[0].ToLower())) {
                        if (CheckAccess(command, source.User, source.Place)) {
                            string syntaxCheck = CheckSyntax(command, ref commandParameters);
                            if (syntaxCheck == null) {
                                ScriptFunctionReturn Return = Program.MainForm.ScriptOutput.CallFunction(source, command.ScriptToCall, command.FunctionToCall, source, commandParameters);
                                if (Return.ReturnType == ScriptFunctionReturnType.ReturnsObject) {
                                    Respond(source, Return.ReturnValue.ToString());
                                }
                            } else {
                                Respond(source, "Syntax error with command '" + commandParameters[0].ToLower() + "': " + syntaxCheck);
                            }
                            return true;
                        } else {
                            return false;
                        }
                    }
                }

                //    switch (m_sExplode[0])
                //    {
                //        // Value commands
                //        #region Trigger
                //        case "trigger":
                //        case "t":
                //            string m_sCmdTriggerData;
                //            if (m_sTrigger.Length != 1)
                //            {
                //                m_sCmdTriggerData = "Length: " + m_sTrigger.Length.ToString();
                //            }
                //            else
                //            {
                //                m_sCmdTriggerData = "Alt + 0" + ((int) (byte) m_sTrigger[0]).ToString();
                //            }
                //            Respond(a_csSource, "My trigger is ' " + m_sTrigger + " ' (" + m_sCmdTriggerData + ").");
                //            break;
                //        #endregion

                //        #region Version
                //        case "version":
                //        case "ver":
                //        case "v":
                //            Respond(a_csSource, "Felbot " + Properties.Resources.Version + " by Joe[x86] and Ribose.");
                //            break;
                //        #endregion

                //        #region Profile
                //        case "profile":
                //        case "prof":
                //            Respond(a_csSource, "This is Felbot profile " + a_csSource.g_frmProfile.Profile.ProfileName + ". Currently " + ProfileControl.GetOpenProfiles.Count + " of " + ProfileControl.ProfileList.Count + " profiles are loaded.");
                //            break;
                //        #endregion

                //        #region Owner
                //        case "owner":
                //        case "o":
                //            Respond(a_csSource, "The current bot owner is " + m_sBotOwner + ".");
                //            break;
                //        #endregion

                //        #region Pingme
                //        case "pingme":
                //        case "getping":
                //        case "ping":
                //        case "myping":
                //        case "p":
                //            ChannelListItem m_sCmdPingUser;
                //            if (m_sCommand.Length < m_sExplode[0].Length + 1)
                //            {
                //                m_sCmdPingUser = a_csSource.g_frmProfile.ChannelList.GetUser(a_csSource.g_sUsername);
                //                if (m_sCmdPingUser != null)
                //                {
                //                    Respond(a_csSource, "Your ping at logon was " + m_sCmdPingUser.Ping.ToString() + "ms.");
                //                }
                //                else
                //                {
                //                    Respond(a_csSource, "You are not logged on, or you are in a silent channel.");
                //                }
                //            }
                //            else
                //            {
                //                string m_sCmdPing = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //                m_sCmdPingUser = a_csSource.g_frmProfile.ChannelList.GetUser(m_sCmdPing.Trim());
                //                if (m_sCmdPingUser != null)
                //                {
                //                    Respond(a_csSource, m_sCmdPingUser.Username + "'s ping at logon was " + m_sCmdPingUser.Ping.ToString() + "ms.");
                //                }
                //                else
                //                {
                //                    Respond(a_csSource, m_sCmdPing.Trim() + " is not in this channel.");
                //                }
                //            }
                //            break;
                //        #endregion

                //        #region Where
                //        case "where":
                //        case "whereareyou":
                //            Respond(a_csSource, "I am in channel " + a_csSource.g_frmProfile.ChannelList.ChannelName + " (" + a_csSource.g_frmProfile.ChannelList.Users.Count.ToString() + " users).");
                //            break;
                //        #endregion

                //        #region Server
                //        case "server":
                //        case "serv":
                //            if (a_csSource.g_frmProfile.Profile.GetSetting("AdvConn", "ProxyUse").ToBoolean(false))
                //            {
                //                Respond(a_csSource, "I am connected to " +
                //                    a_csSource.g_frmProfile.Profile.GetSetting("Connection", "Server").ToString("") +
                //                    " through the " +
                //                    a_csSource.g_frmProfile.Profile.GetSetting("AdvConn", "ProxyProtocol").ToString("") +
                //                    " proxy " +
                //                    a_csSource.g_frmProfile.Profile.GetSetting("AdvConn", "ProxyServer").ToString("") +
                //                    ":" +
                //                    a_csSource.g_frmProfile.Profile.GetSetting("AdvConn", "ProxyPort").ToString("") + ".");
                //            }
                //            else
                //            {
                //                Respond(a_csSource, "I am connected to " +
                //                    a_csSource.g_frmProfile.Profile.GetSetting("Connection", "Server").ToString() +
                //                    ".");
                //            }
                //            break;
                //        #endregion

                //        #region CQ
                //        case "cq":
                //        case "clearqueue":
                //            a_csSource.g_frmProfile.PacketThread.ClearQueue();
                //            Respond(a_csSource, "Queue cleared.");
                //            break;
                //        #endregion

                //        #region SCQ
                //        case "scq":
                //            a_csSource.g_frmProfile.PacketThread.ClearQueue();
                //            break;
                //        #endregion

                //        // Repeat commands
                //        #region Say
                //        case "say":
                //        case "s":
                //        case "repeat":
                //        case "echo":
                //            if (m_sCommand.Length > m_sExplode[0].Length + 1)
                //            {
                //                string m_sCmdSay = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //                Respond(a_csSource, m_sCmdSay);
                //            }
                //            break;
                //        #endregion

                //        #region Expand
                //        case "expand":
                //        case "exp":
                //            if (m_sCommand.Length > m_sExplode[0].Length + 1)
                //            {
                //                string m_sCmdExpand1 = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //                string m_sCmdExpand2 = " ";
                //                for (int k = 0; k < m_sCmdExpand1.Length; k++)
                //                {
                //                    m_sCmdExpand2 += m_sCmdExpand1[k] + " ";
                //                }
                //                Respond(a_csSource, m_sCmdExpand2);
                //            }
                //            break;
                //        #endregion

                //        #region Shout
                //        case "shout":
                //            if (m_sCommand.Length > m_sExplode[0].Length + 1)
                //            {
                //                string m_sCmdShout = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //                Respond(a_csSource, m_sCmdShout.ToUpper());
                //            }
                //            break;
                //        #endregion

                //        #region Reverse
                //        case "reverse":
                //            if (m_sCommand.Length > m_sExplode[0].Length + 1)
                //            {
                //                string m_sCmdReverse = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //                string m_sCmdReverse2 = "";
                //                for (int j = m_sCmdReverse.Length; j > 0; j--)
                //                {
                //                    m_sCmdReverse2 += m_sCmdReverse[j - 1];
                //                }
                //                Respond(a_csSource, m_sCmdReverse2);
                //            }
                //            break;
                //        #endregion

                //        // Action commands
                //        #region JoinHome
                //        case "joinhome":
                //        case "home":
                //            a_csSource.g_frmProfile.PacketThread.Send_SID_JOINCHANNEL(false, false, a_csSource.g_frmProfile.Profile.GetSetting("Channel", "Home").ToString());
                //            break;
                //        #endregion

                //        #region Join
                //        case "join":
                //        case "j":
                //            if (a_csSource.g_cspSource == CommandSourcePlace.InBot)
                //                return false;
                //            if (m_sCommand.Length > m_sExplode[0].Length + 1)
                //            {
                //                string m_sCmdJoin = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //                a_csSource.g_frmProfile.PacketThread.AddQueue("/join " + m_sCmdJoin);
                //            }
                //            break;
                //        #endregion

                //        #region ForceJoin
                //        case "forcejoin":
                //        case "fj":
                //            if (m_sCommand.Length > m_sExplode[0].Length + 1)
                //            {
                //                string m_sCmdForceJoin = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //                a_csSource.g_frmProfile.PacketThread.Send_SID_JOINCHANNEL(false, false, m_sCmdForceJoin);
                //            }
                //            break;
                //        #endregion

                //        #region QuickReJoin
                //        case "quickrejoin":
                //        case "qrj":
                //            a_csSource.g_frmProfile.PacketThread.Send_SID_LEAVECHAT();
                //            a_csSource.g_frmProfile.PacketThread.Send_SID_JOINCHANNEL(false, false, a_csSource.g_frmProfile.ChannelList.ChannelName);
                //            break;
                //        #endregion

                //        #region ReJoin
                //        case "rejoin":
                //        case "rj":
                //        case "resign":
                //            string m_sCmdReJoin = a_csSource.g_frmProfile.ChannelList.ChannelName;
                //            a_csSource.g_frmProfile.PacketThread.AddQueue("/join Felbot " + a_csSource.g_frmProfile.PacketThread.UniqueUsername + " ReJoin");
                //            a_csSource.g_frmProfile.PacketThread.AddQueue("/join " + m_sCmdReJoin);
                //            break;
                //        #endregion

                //        // Clan commands
                //        #region GetClanMotd
                //        case "getclanmotd":
                //            if (a_csSource.g_frmProfile.PacketThread.Client.Equals("WAR3") || a_csSource.g_frmProfile.PacketThread.Client.Equals("W3XP"))
                //            {
                //                if (a_csSource.g_frmProfile.ClanList.g_sClanTag != null)
                //                {
                //                    g_iCookie = ClanQueueMember.GenerateCookie();
                //                    g_csLastSource = a_csSource;
                //                    a_csSource.g_frmProfile.PacketThread.Send_SID_CLANMOTD(g_iCookie);
                //                }
                //                else
                //                {
                //                    Respond(a_csSource, "The bot is not in a Clan.");
                //                }
                //            }
                //            else
                //            {
                //                Respond(a_csSource, "The bot is not on WarCraft III.");
                //            }
                //            break;
                //        #endregion

                //        // Clan commands
                //        #region GetClanMotd
                //        case "getclaninformation":
                //        case "getclaninfo":
                //            if (a_csSource.g_frmProfile.PacketThread.Client.Equals("WAR3") || a_csSource.g_frmProfile.PacketThread.Client.Equals("W3XP"))
                //            {
                //                if (a_csSource.g_frmProfile.ClanList.g_sClanTag != null)
                //                {
                //                    Respond(a_csSource, "Clan " + a_csSource.g_frmProfile.ClanList.g_sClanTag + " (" + a_csSource.g_frmProfile.ClanList.g_sClanName + ") has " + a_csSource.g_frmProfile.ClanList.OnlineUsers.Count.ToString() + " online of " + a_csSource.g_frmProfile.ClanList.Users.Count.ToString() + " members.");
                //                    Respond(a_csSource, "It is led by chieftain " + a_csSource.g_frmProfile.ClanList.Chieftain.Username + (a_csSource.g_frmProfile.ClanList.Shamans.Count > 0 ? " and the shamans " + a_csSource.g_frmProfile.ClanList.ShamanList + "." : ""));
                //                }
                //                else
                //                {
                //                    Respond(a_csSource, "The bot is not in a Clan.");
                //                }
                //            }
                //            else
                //            {
                //                Respond(a_csSource, "The bot is not on WarCraft III.");
                //            }
                //            break;
                //        #endregion

                //        //#region ClanExists
                //        //case "clanexists":
                //        //    if (a_ptCaller.Client.Equals("WAR3") || a_ptCaller.Client.Equals("W3XP"))
                //        //    {
                //        //        if (m_sExplode.Length > 0)
                //        //        {
                //        //            string m_sCmdClanExists = m_sCommand.Substring(m_sExplode[0].Length + 1);
                //        //            if (m_sCmdClanExists.Length > 2 && m_sCmdClanExists.Length < 4)
                //        //            {
                //        //                if (ClanList.g_iClanFindCandidates_Cookie == 0)
                //        //                {
                //        //                    Respond(a_csSource, a_ptCaller, "Checking clan " + m_sCmdClanExists + "..");
                //        //                    ClanList.g_sClanTag = m_sCmdClanExists;
                //        //                    int m_iCmdClanExistsCookie = BitConverter.ToInt32(BattleNetUtil.StringToDWORD("FbCE"), 0);
                //        //                    ClanList.g_iClanFindCandidates_Cookie = m_iCmdCreateClanCookie;
                //        //                    a_ptCaller.SendPacket70(m_iCmdClanExistsCookie, m_sCmdClanExists);
                //        //                }
                //        //                else
                //        //                {
                //        //                    Respond(a_csSource, a_ptCaller, "This bot is waiting for SID_CLANFINDCANDIDATES to return.");
                //        //                }
                //        //            }
                //        //            else
                //        //            {
                //        //                Respond(a_csSource, a_ptCaller, "Invalid clan tag \"" + m_sCmdClanExists + "\".");
                //        //            }
                //        //        }
                //        //        else
                //        //        {
                //        //            Respond(a_csSource, a_ptCaller, "Provide a clan tag.");
                //        //        }
                //        //    }
                //        //    else
                //        //    {
                //        //        Respond(a_csSource, a_ptCaller, "This bot must be on WarCraft III.");
                //        //    }
                //        //    break;
                //        //#endregion

                //        #region Default
                //        default:
                //            return false;
                //        #endregion
                //    }
            }
            #endregion

            return false;
        }

        /// <summary>
        /// Checks the syntax of a command with Commands.fbx.
        /// </summary>
        /// <param name="command">The XmlCommand object.</param>
        /// <param name="arguments">The arguments provided.</param>
        /// <returns>
        /// A string containing null if the syntax was valid, and an
        /// error string to output if invalid.
        /// </returns>
        private static string CheckSyntax(XmlCommand command, ref string[] arguments) {
            if (command.Syntax == null)
                return null;

            List<XmlCmdArgument> SyntaxArgs = command.Syntax.Arguments;
            if (SyntaxArgs.Count == 0 && arguments.Length > 1)
                return "Arguments found when 0 specified.";

            List<XmlCmdArgument> SyntaxArgsOrdered = new List<XmlCmdArgument>(SyntaxArgs.Count);
            foreach (XmlCmdArgument SyntaxArg in SyntaxArgs) {
                SyntaxArgsOrdered.Insert(SyntaxArg.Order, SyntaxArg);
            }
            SyntaxArgsOrdered.TrimExcess();

            for (int i = 0; i < SyntaxArgsOrdered.Count; i++) {
                if (arguments.Length < i || arguments[i] == "" && !SyntaxArgsOrdered[i].Optional)
                    return "Required argument omitted '" + SyntaxArgsOrdered[i].Name + "'.";

                switch (SyntaxArgsOrdered[i].ValueType) {
                    case "rest":
                        string[] argumentsrest = new string[i];
                        for (int j = 0; j < arguments.Length; j++) {
                            if (j < i)
                                argumentsrest[j] = arguments[j];
                            else
                                argumentsrest[i - 1] += " " + arguments[j];
                        }
                        arguments = argumentsrest;
                        return null;

                    default:
                    case "word":
                        //no special cases
                        break;

                    case "number":
                    case "decimal":
                        decimal d;
                        if (!decimal.TryParse(arguments[i], NumberStyles.Any, NumberFormatInfo.CurrentInfo, out d))
                            return "Argument '" + SyntaxArgsOrdered[i].Name + "' is not a valid number.";
                        break;

                    case "integer":
                        decimal n;
                        if (!decimal.TryParse(arguments[i], NumberStyles.Any, NumberFormatInfo.CurrentInfo, out n))
                            return "Argument '" + SyntaxArgsOrdered[i].Name + "' is not a valid integer.";
                        break;

                    case "percent":
                        decimal p;
                        if (!decimal.TryParse(arguments[i], NumberStyles.Any, NumberFormatInfo.CurrentInfo, out p))
                            if (p < 0 || p > 100)
                                return "Argument '" + SyntaxArgsOrdered[i].Name + "' is not a valid percentage.";
                        break;
                }
            }

            return null;
        }

        /// <summary>
        /// Checks the access of the user with the access
        /// required by the command in Commands.fbx and USers.fbx.
        /// </summary>
        /// <param name="command">The XmlCommand object.</param>
        /// <param name="username">The username of the user.</param>
        /// <param name="sourcePlace">The place of command origin.</param>
        /// <returns></returns>
        private static bool CheckAccess(XmlCommand command, ChannelUser username, CommandSourcePlace sourcePlace) {
            if (sourcePlace == CommandSourcePlace.InBot || sourcePlace == CommandSourcePlace.InBotExternal)
                return true;

            XmlEntry entry = UserEntryControl.GetCumulativeEntry(username);
            
            if (entry == null)
                return false;

            switch (command.Requires.Check) {
                default:
                case XmlCmdCheckType.Or:
                    foreach (string flag in command.Requires.Flags) {
                        if (entry.Has.Flags.Contains(flag)) {
                            return true;
                        }
                    }
                    return false;
                case XmlCmdCheckType.And:
                    foreach (string flag in command.Requires.Flags) {
                        if (!entry.Has.Flags.Contains(flag)) {
                            return false;
                        }
                    }
                    return true;
                case XmlCmdCheckType.Xor:
                    int flagcount = 0;
                    foreach (string flag in command.Requires.Flags) {
                        if (entry.Has.Flags.Contains(flag)) {
                            flagcount++;
                        }
                    }
                    if (flagcount == 1)
                        return true;
                    else
                        return false;
                case XmlCmdCheckType.Not:
                    foreach (string flag in command.Requires.Flags) {
                        if (entry.Has.Flags.Contains(flag)) {
                            return false;
                        }
                    }
                    return true;
            }
        }

        /// <summary>
        /// Outputs the response of a command to the command source location.
        /// </summary>
        /// <param name="source">The command source object.</param>
        /// <param name="text">The response text.</param>
        private static void Respond(CommandSource source, string text) {
            string d2Star = "";
            if (frmProfile.GetForm(source.Profile.ProfileName).PacketThread.Client.Equals("D2DV") || frmProfile.GetForm(source.Profile.ProfileName).PacketThread.Client.Equals("D2XP"))
                d2Star = "*";
            switch (source.Place) {
                case CommandSourcePlace.InBot:
                    frmProfile.GetForm(source.Profile.ProfileName).RichTextBox.AddTextNodes(FCSControl.GetTextNode(FCSObjects.Chatroom_Information_Command, text));
                    break;

                case CommandSourcePlace.Channel:
                    if (ProfileControl.Global.GetSetting("Interaction", "CommandsWhisperResponse").ToBoolean(false))
                        frmProfile.GetForm(source.Profile.ProfileName).PacketThread.AddQueue("/w " + d2Star + source.User + " " + text);
                    else
                        frmProfile.GetForm(source.Profile.ProfileName).PacketThread.AddQueue(text);
                    break;

                case CommandSourcePlace.InBotExternal:
                    frmProfile.GetForm(source.Profile.ProfileName).PacketThread.AddQueue(text);
                    break;

                case CommandSourcePlace.Emote:
                    frmProfile.GetForm(source.Profile.ProfileName).PacketThread.AddQueue("/me " + text);
                    break;

                case CommandSourcePlace.Whisper:
                    frmProfile.GetForm(source.Profile.ProfileName).PacketThread.AddQueue("/w " + d2Star + source.User + " " + text);
                    break;

            }
        }

        ///// <summary>
        ///// This is the return of the !clanexists command.
        ///// </summary>
        //public static void ClanFindCandidates(CommandSource a_csSource, BattleNetPacketThread a_ptCaller, byte a_bStatus)
        //{
        //    switch (a_bStatus)
        //    {
        //        case 0x00:
        //            Respond(a_csSource, a_ptCaller, "That clan does not exist. You may create it.");
        //            break;
        //        case 0x01:
        //            Respond(a_csSource, a_ptCaller, "That clan exists.");
        //            break;
        //        case 0x02:
        //            Respond(a_csSource, a_ptCaller, "This bot has created a clan too recently.");
        //            break;
        //        case 0x08:
        //            Respond(a_csSource, a_ptCaller, "This bot is in a clan.");
        //            break;
        //        case 0x0A:
        //            Respond(a_csSource, a_ptCaller, "Invalid clan tag.");
        //            break;
        //        default:
        //            Respond(a_csSource, a_ptCaller, "That clan cannot be created. (0x" + a_bStatus.ToString("X") + ")");
        //            break;
        //    }
        //}


        ///// <summary>
        ///// The return of !getclanmotd.
        ///// </summary>
        //public static void GetClanMotdComplete()
        //{
        //    if (g_csLastSource.g_frmProfile.ClanList.g_sClanMotd != "")
        //    {
        //        Respond(g_csLastSource, "The current Clan MOTD is: " + g_csLastSource.g_frmProfile.ClanList.g_sClanMotd);
        //    }
        //    else
        //    {
        //        Respond(g_csLastSource, "No Clan MOTD is currently set.");
        //    }
        //    g_iCookie = 0;
        //}
    }

    /// <summary>
    /// This class specifies where a command originated.
    /// </summary>
    public class CommandSource {
        private CommandSourcePlace m_Source;
        private ChannelUser m_User;
        private Profile m_Profile;

        /// <summary>Gives the type of message sent as an enumeration.</summary>
        public CommandSourcePlace Place {
            get {
                return m_Source;
            }
        }

        /// <summary>The username of the sender.</summary>
        public ChannelUser User {
            get {
                return m_User;
            }
        }
        
        /// <summary>The profile where the command is issued.</summary>
        public Profile Profile {
            get {
                return m_Profile;
            }
        }


        /// <summary>Creates a new source object.</summary>
        /// <param name="source">The type of message sent.</param>
        /// <param name="username">The username of the sender.</param>
        /// <param name="profile">The profile where command is issued.</param>
        public CommandSource(CommandSourcePlace source, ChannelUser user, Profile profile) {
            m_Source = source;
            m_User = user;
            m_Profile = profile;
        }
    }

    /// <summary>
    /// Specifies the type of message the command was sent as.
    /// </summary>
    public enum CommandSourcePlace {
        /// <summary>The command occured in-bot (by the bot owner).</summary>
        InBot = 1,
        /// <summary>The command occured in-bot but made external with //command.</summary>
        InBotExternal = 2,
        /// <summary>The command occured in the channel by another user.</summary>
        Channel = 3,
        /// <summary>The command was emoted.</summary>
        Emote = 4,
        /// <summary>The command was whispered to the bot.</summary>
        Whisper = 5,
        /// <summary>The call was an event call.</summary>
        Event = 6
    }
}
